package br.requisiteworks.requisito.modelo.dao.jpa;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import br.requisiteworks.modelo.Projeto;
import br.requisiteworks.requisito.modelo.Requisito;
import br.requisiteworks.requisito.modelo.TipoRequisito;
import br.requisiteworks.requisito.modelo.dao.RequisitoDao;
import br.requisiteworks.util.persistencia.ErroBancoDados;
import br.requisiteworks.util.persistencia.ResultadoVazio;

@Repository
public class JpaRequisitosDao implements RequisitoDao {

	@PersistenceContext
	private EntityManager em;

	@Transactional(propagation = Propagation.REQUIRED)
	public void insert(Requisito requisito) throws ErroBancoDados {
		try {

			em.persist(requisito);
		} catch (PersistenceException e) {
			throw new ErroBancoDados(
					"Ocorreu um erro ao adicionar tipo de requisito: "
							+ requisito, e);
		}
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public void update(Requisito requsito) {
		em.merge(requsito);
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public void delete(Requisito requsito) {
		requsito.setRegistroAtivo(false);
		em.merge(requsito);
	}

	@Override
	@Transactional
	public Requisito select(int numero) throws ResultadoVazio {
		Requisito requisito = em.find(Requisito.class, numero);

		if (requisito == null) {
			throw new ResultadoVazio(
					"Nao foi encontrado tipo de requisito de numero = "
							+ numero);
		} else {
			requisito.getAtributos().size();
		}

		return requisito;
	}

	@Override
	public List<Requisito> select(TipoRequisito tipo) throws ResultadoVazio {
		TypedQuery<Requisito> query = em
				.createQuery(
						"SELECT r FROM Requisito r WHERE r.tipoRequisito=:tipo ORDER BY r.numero",
						Requisito.class);

		query.setParameter("tipo", tipo);

		List<Requisito> resultado = query.getResultList();

		ResultadoVazio.verificaVazio(resultado,
				"Nao foi encontrado tipo de requisito com nome = " + tipo);

		return resultado;
	}

	@Override
	@Transactional
	public List<Requisito> select(Projeto projeto) throws ResultadoVazio {
		TypedQuery<Requisito> query = this.em
				.createQuery(
						"SELECT r FROM Requisito r WHERE r.projeto=:projeto and r.registroAtivo=true ORDER BY r.numero",
						Requisito.class);

		query.setParameter("projeto", projeto);

		List<Requisito> requisitos = query.getResultList();

		ResultadoVazio.verificaVazio(requisitos,
				"Nao foi encontrado requisito para o projeto " + projeto);

		for (Requisito req : requisitos) {
			req.getAtributos().size();
		}

		return requisitos;
	}

	@Override
	public List<Requisito> select() throws ResultadoVazio {
		TypedQuery<Requisito> query = this.em
				.createQuery(
						"SELECT r FROM Requisito r WHERE r.registroAtivo=true ORDER BY r.numero",
						Requisito.class);

		List<Requisito> result = query.getResultList();

		ResultadoVazio.verificaVazio(result);

		return result;
	}

	public List<Requisito> select(Projeto projeto, TipoRequisito tipoRequisito)
			throws ResultadoVazio {
		TypedQuery<Requisito> query = this.em
				.createQuery(
						"SELECT r FROM Requisito r WHERE r.projeto=:projeto AND r.tipo=:tipo AND r.registroAtivo=true ORDER BY r.numero",
						Requisito.class);

		query.setParameter("projeto", projeto);
		query.setParameter("tipo", tipoRequisito);

		List<Requisito> requisitos = query.getResultList();

		ResultadoVazio.verificaVazio(requisitos,
				"Nao foi encontrado requisito para o projeto " + projeto);

		return requisitos;
	}
}
